package org.rsna.radlex;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.stanford.smi.protege.model.Cls;
import edu.stanford.smi.protege.model.Instance;
import edu.stanford.smi.protege.model.KnowledgeBase;
import edu.stanford.smi.protege.model.Slot;

public class CommonTasks {

	public static void displayErrors(Collection<Cls> errors) {
		if (errors.size() > 0) {
        	Iterator<Cls> i = errors.iterator();
            while (i.hasNext()) {
                System.out.println("Error: " + i.next());
            }
        }
	}

	
	
	
	public static Cls getClassByRID(String rid, KnowledgeBase kb)
	{
		
		// get all classes back matching the name (RID), there should be only one, so we'll just grab the first
        Cls myClass = (Cls)kb.getClsNameMatches(rid, 1).iterator().next();
     
		return myClass;
	}
	
	
	public static HashMap<String, String> getAllNames(KnowledgeBase kb) {
		Iterator<Cls> allClassesIter = kb.getClses().iterator();
		HashMap<String, String> nameHash = new HashMap<String, String>();
        while( allClassesIter.hasNext() ){
        	Cls singleClass = allClassesIter.next();
        	String prefName = findPreferredName(singleClass);
        	if( nameHash.containsKey(prefName)) {
        		System.out.println("Duplicate Preferred Name: " +prefName);
        	}
        	if( prefName != null ) {
        		nameHash.put(prefName.toLowerCase(), singleClass.getName());
        	} else {
        		System.out.println("Null Preferred Name for RID: "+singleClass.getName());
        	}
        }
        return nameHash;
	}
	
	public static HashMap<String, String> getAllSomething(KnowledgeBase kb, String something) {
		Iterator<Cls> allClassesIter = kb.getClses().iterator();
		HashMap<String, String> nameHash = new HashMap<String, String>();
        while( allClassesIter.hasNext() ){
        	Cls singleClass = allClassesIter.next();


    		Set<String> somethingForClass = getSomethingForClass(singleClass, something);

    		Iterator<String> somethingIterator = somethingForClass.iterator();
    		while( somethingIterator.hasNext() ) {
    			String somethingName = somethingIterator.next();
    			if( nameHash.containsKey(somethingName)) {
    				System.out.println("DUPLICATE "+something+":  "+something+": "+somethingName+" RID#1: "+singleClass.getName()+" RID#2:"+nameHash.get(somethingName));
    			} else {
    				nameHash.put(somethingName.toLowerCase(), singleClass.getName());
    			}
    		}

        }
        return nameHash;
	}	

	
	public static HashMap<String, String> getAllNonEnglishNames(KnowledgeBase kb) {
		
		return getAllSomething(kb, "Non-English_name");
	}

	
	
	public static Set<String> getNonEnglishForClass(Cls singleClass) 
	{
		return getSomethingForClass(singleClass, "Non-English_name");
	}

	
	//custom mj trying to retrieve Synonyms from newer version of  (3-28-2011)radlex.pprj
	public static HashMap<String, String> getAllSynonymsCUSTOM(KnowledgeBase kb) {
		Iterator<Cls> allClassesIter = kb.getClses().iterator();
		HashMap<String, String> nameHash = new HashMap<String, String>();
        while( allClassesIter.hasNext() ){
        	Cls singleClass = allClassesIter.next();


    		Set<String> synonymsForClass = getSynonymsForClass(singleClass);

    		Iterator<String> synIterator = synonymsForClass.iterator();
    		while( synIterator.hasNext() ) {
    			String synName = synIterator.next();
    			if( nameHash.containsKey(synName)) {
    				System.out.println("DUPLICATE SYNONYM:  Synonym: "+synName+" RID#1: "+singleClass.getName()+" RID#2:"+nameHash.get(synName));
    			} else {
    				//surrounding put with try catch exception to try to avoid null pointer error---mj
    				try
    				{
    				nameHash.put(synName.toLowerCase(), singleClass.getName());
    				}
    				catch(Exception x){}
    			}
    		}

        }
        return nameHash;
	}
	
	public static HashMap<String, String> getAllSynonyms(KnowledgeBase kb) {
		
		return getAllSomething(kb, "Synonym");
//		Iterator<Cls> allClassesIter = kb.getClses().iterator();
//		HashMap<String, String> nameHash = new HashMap<String, String>();
//        while( allClassesIter.hasNext() ){
//        	Cls singleClass = allClassesIter.next();
//
//
//    		Set<String> synonymsForClass = getSynonymsForClass(singleClass);
//
//    		Iterator<String> synIterator = synonymsForClass.iterator();
//    		while( synIterator.hasNext() ) {
//    			String synName = synIterator.next();
//    			if( nameHash.containsKey(synName)) {
//    				System.out.println("DUPLICATE SYNONYM:  Synonym: "+synName+" RID#1: "+singleClass.getName()+" RID#2:"+nameHash.get(synName));
//    			} else {
//    				nameHash.put(synName.toLowerCase(), singleClass.getName());
//    			}
//    		}
//
//        }
//        return nameHash;
	}
	
	public static HashMap<String, String> getAllAcronyms(KnowledgeBase kb) 
	{
		return getAllSomething(kb, "Acronym");
	}
	

	public static Set<String> getSynonymsForClass(Cls singleClass) 
	{
		return getSomethingForClass(singleClass, "Synonym");
	}
	
	private static Set<String> getSomethingForClass(Cls singleClass, String something) 
	{
		Iterator<Slot> slotIter = singleClass.getOwnSlots().iterator();
		Set<String> myList = new HashSet<String>();
		while( slotIter.hasNext() )
		{
			Slot mySlot = slotIter.next();
			if(something.equals(mySlot.getName()) ) 
			{
				Iterator iter2 = singleClass.getOwnSlotValues(mySlot).iterator();
				while( iter2.hasNext() )
				{
					String theSyn = null;
					Object theObj = iter2.next();
					if( theObj instanceof Instance) 
					{
						Instance theSynInstance = (Instance)theObj;
						theSyn = (String)CommonTasks.getSlotValue(theSynInstance, "name");
					} 
					else 
					{
						theSyn = (String)theObj;
					}
					myList.add(theSyn);
				}
			}
		}
		return myList;
	}
	
	
	/**
	 * @param singleClass
	 * @param something
	 * @return
	 */
	public static Set<Object> getSomethingAsObjectForClass(Cls singleClass, String something) {
		Iterator<Slot> slotIter = singleClass.getOwnSlots().iterator();
		Set<Object> myList = new HashSet<Object>();
		while( slotIter.hasNext() )
		{
			Slot mySlot = slotIter.next();
			if(something.equals(mySlot.getName()) ) 
			{
				Iterator iter2 = singleClass.getOwnSlotValues(mySlot).iterator();
				while( iter2.hasNext() )
				{
					myList.add(iter2.next());
				}
			}
		}
		return myList;				
	}
	
	
	//??????
	public static Set<String> getNamesForClass(Cls singleClass)
	{
		return getSomethingForClass(singleClass, "Preferred_name");
	}


	public static void generateDeprecatedMap(KnowledgeBase kb,
			HashMap<String, String> allDeprecated) {
		Iterator<Cls> allClassesIter = kb.getClses().iterator();
        while( allClassesIter.hasNext() ){
        	Instance singleClass = allClassesIter.next();

        	Object deprecatedId = getSlotValue(singleClass, "Deprecated_RID");
        	if (deprecatedId != null ) { allDeprecated.put((String)deprecatedId, singleClass.getName()); }
        }
	}

	/**
	 * This assumes only 1 value, it just grabs the first it finds and returns it
	 * @param cls
	 * @param slotName
	 * @return
	 */
	public static Object getSlotValue(Instance cls, String slotName) {
		Object something = null;
		Iterator<Slot> slotIter = cls.getOwnSlots().iterator();
		// loop through all the slots, to find the slot with the desired name
		while( slotIter.hasNext() ){
			Slot mySlot = slotIter.next();
			if(slotName.equals(mySlot.getName()) ) {
				Iterator iter2 = cls.getOwnSlotValues(mySlot).iterator();
				if(iter2.hasNext() ) { something = iter2.next(); }
				break;
			}
		}

		return something;
	}
	
	public static Slot getSlotByName(Instance cls, String slotName) {
		Slot mySlot = null;
		Iterator<Slot> slotIter = cls.getOwnSlots().iterator();
		// loop through all the slots, to find the slot with the desired name
		while( slotIter.hasNext() ){
			mySlot = slotIter.next();
			if(slotName.equals(mySlot.getName()) ) {
				break;
			}
		}

		return mySlot;	
	}


	public static void setSlotValue(Instance cls, String slotName, Object slotValue) 
	{
		Iterator<Slot> slotIter = cls.getOwnSlots().iterator();
		// loop through all the slots, to find the slot with the desired name
		while( slotIter.hasNext() ){
			Slot mySlot = slotIter.next();
			if(slotName.equals(mySlot.getName()) ) {
				cls.setOwnSlotValue(mySlot, slotValue);
				break;
			}
		}
		
	}


	public static String findPreferredName(Instance cls) {
		String preferredName = null;

		Object slotValueObj = CommonTasks.getSlotValue(cls, "Preferred_name");
		// should be a instance
		if( slotValueObj instanceof Instance) {
			// alright then, let's check the values of this class
			Instance myClass = (Instance) slotValueObj;
			preferredName = (String)CommonTasks.getSlotValue(myClass, "name");
		}

		return preferredName;
	}
}
